﻿using System.Globalization;
using System;
using System.Collections;
using System.IO;
using UMC.Net;
using System.Net;
using UMC.Data;
using System.Threading;
using System.Diagnostics;
// using System.IO.Pipes;
using System.Runtime.InteropServices;
using System.Linq;
using System.Reflection;
using SkiaSharp;
using System.Collections.Generic;
using Microsoft.VisualBasic;
using NSec.Cryptography;
using System.Net.Sockets;


namespace UMC.ITME
{
    //dotnet publish -r linux-x64  -c Release /p:PublishSingleFile=true /p:PublishTrimmed=true
    public class Program
    {
        public static void Main(string[] args)
        {
            Start(args, () => { }, new Dictionary<string, Func<String>>());
        }
        public static void Start(string[] args, Action action, Dictionary<string, Func<String>> pairs, Func<UMC.ITME.WebServlet> func = null)
        {

            var variable = System.Environment.GetEnvironmentVariable("UMC");

            if (String.IsNullOrEmpty(variable))
            {
                if (args.Length > 0)
                {
                    variable = args[0];
                }
            }
            else if (variable == "daemon")
            {
                while (true)
                {
                    //
                    var process = Excel($"main daemon", true);
                    try
                    {
                        using (StreamReader reader = process?.StandardError)
                        {
                            string stdout = reader?.ReadToEnd();
                            if (String.IsNullOrEmpty(stdout) == false)
                            {
                                var filename = UMC.Data.Reflection.ConfigPath(String.Format("Static\\log\\App\\Error\\ITME\\{0:yy-MM-dd}.log", DateTime.Now));
                                if (!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(filename)))
                                {
                                    System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(filename));
                                }

                                File.AppendAllText(filename, stdout);// $"{D
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                    finally
                    {
                        process?.WaitForExit();
                        process?.Dispose();
                    }
                }

                return;

            }
            else
            {
                args = variable.Split(' ', StringSplitOptions.RemoveEmptyEntries);
                variable = args[0];
            }
            if (String.IsNullOrEmpty(variable) == false)
            {
                switch (variable)
                {
                    // case "daemon":

                    case "main":
                        if (IsRun(out var rePath) == false)
                        {
                            // Console.WriteLine(args.Length);
                            // if (args.Length == 1)
                            // {
                            // AppDomain.CurrentDomain.UnhandledException += UnhandledException;
                            // }
                            StartUp(new string[0], action, pairs, func);

                        }
                        else
                        {
                            StartUp(new string[] { rePath }, action, pairs, func);


                        }
                        return;
                    case "image":
                        {
                            using (System.IO.Stream stream = typeof(ITME.WebServlet).Assembly//UMC.Proxy
                                        .GetManifestResourceStream("UMC.ITME.Resources.app.png"))
                            {
                                using SKCodec sKCodec = SKCodec.Create(stream);
                            }

                        }
                        return;
                }
            }
            Console.WriteLine();
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.WriteLine("#  [start] \t\t开启IT管理引擎（ITME）服务");
            // Console.WriteLine("#  [http  0-9] \t\t重置Http默认端口");
            // Console.WriteLine("#  [https 0-9] \t\t重置Https默认端口");
            // Console.WriteLine("#  [repost] \t\t查看外网转发服务");
            // Console.WriteLine("#  [repost start] \t开启外网转发服务");
            // Console.WriteLine("#  [repost stop] \t停止外网转发服务");
            Console.WriteLine("#  [stop] \t\t停止IT管理引擎（ITME）服务");
            Console.WriteLine("#  [exit] \t\t退出指令程序");

            Console.WriteLine();
            Console.ResetColor();

            ConfigDbProvider();

            if (args.Length > 0)
            {
                IsDo = false;
                Command(args);
            }
            else
            {
                IsDo = true;
                if (IsRun() == false)
                {
                    Excel("main");
                    if (OperatingSystem.IsWindows())
                    {
                        Console.Write("特别注意：");
                        Console.ForegroundColor = ConsoleColor.DarkRed;
                        Console.WriteLine("需要退出程序时，请用[exit]指令退出当前程序");
                        Console.WriteLine();
                        Console.ResetColor();
                    }
                    else
                    {
                        IsDo = false;
                    }
                    int time = 0;
                    while (time < 20)
                    {
                        System.Threading.Thread.Sleep(500);
                        if (IsRun())
                        {
                            break;
                        }
                        time++;
                    }
                }
                Write("info");
                while (IsDo)
                {
                    Console.ForegroundColor = ConsoleColor.Magenta;
                    Console.Write("指令：");
                    Console.ResetColor();

                    var cmds = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);

                    if (cmds.Length > 0)
                    {
                        if (cmds[0] == "exit")
                        {
                            break;
                        }
                        Command(cmds);

                    }
                }
            }
        }
        static bool IsDo = false;

        public static bool IsRun()
        {
            return IsRun(out var _);
        }
        public static int AdminPort = 5188;
        public static bool IsRun(out String rootPath)
        {
            rootPath = String.Empty;

            try
            {
                var tcpClient = NamedPipe();
                // tcpClient.Connect("127.0.0.1", AdminPort);
                using (var pipeClient = new NetworkStream(tcpClient, true))
                {

                    var key = UMC.Data.Utility.Parse36Encode(UMC.Data.Utility.IntParse(new Guid(UMC.Data.Utility.MD5(System.AppContext.BaseDirectory)))); ;

                    // pipeClient.Connect(10);
                    var ls = new byte[0x200];
                    ls[0] = 13;
                    pipeClient.Write(ls, 0, $"check {key}".WriteBytes(ls, 1) + 1);
                    var l = pipeClient.Read(ls, 0, ls.Length);
                    if (l > 0)
                    {
                        Console.WriteLine("主程序目录：");
                        Console.ForegroundColor = ConsoleColor.DarkRed;
                        rootPath = System.Text.Encoding.UTF8.GetString(ls, 0, l);
                        Console.WriteLine(rootPath);//System.Text.Encoding.UTF8.GetString(ls, 0, l));
                        Console.WriteLine();
                        Console.ResetColor();

                    }
                    else
                    {
                        rootPath = Utility.MapPath("~");
                    }
                    pipeClient.Close();
                    return true;

                }
                // tcpClient.Close();
            }
            catch //(Exception ex)
            {
                // Console.WriteLine(ex.Message);
                return false;
            }
            finally
            {
            }

        }
        static Socket NamedPipe()
        {
            Socket command;
            if (OperatingSystem.IsWindows())
            {

                command = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                command.Connect(new IPEndPoint(IPAddress.Loopback, Program.AdminPort));


            }
            else
            {
                var endpoint = new UnixDomainSocketEndPoint("/tmp/itme.sock");

                command = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
                command.Connect(endpoint);

            }

            return command;
        }
        static void Write(params string[] args)
        {
            var tcpClient = NamedPipe();
            try
            {
                var key = UMC.Data.Utility.Parse36Encode(UMC.Data.Utility.IntParse(new Guid(UMC.Data.Utility.MD5(System.AppContext.BaseDirectory)))); ;

                using (var pipeClient = new NetworkStream(tcpClient, true))
                {
                    // var bufer=new Buffer
                    var ls = new byte[0x200];
                    ls[0] = 13;
                    pipeClient.Write(ls, 0, String.Join(" ", args).WriteBytes(ls, 1) + 1);

                    int size = ls.Length;
                    int index = 0;
                    int total = 0;
                    int start = 0;
                    do
                    {
                        total = pipeClient.Read(ls, index, size) + index;

                        for (var i = 0; i < total; i++)
                        {
                            switch (ls[i])
                            {
                                case 10:
                                    if (start < i)
                                    {

                                        Console.Write(System.Text.Encoding.UTF8.GetString(ls, start, i - start));

                                    }
                                    start = i + 1;
                                    Console.ResetColor();
                                    Console.WriteLine();
                                    break;
                                case 12:
                                    if (start < i)
                                    {
                                        Console.Write(System.Text.Encoding.UTF8.GetString(ls, start, i - start));
                                    }
                                    start = i + 1;
                                    Console.ResetColor();
                                    break;
                                case 13:

                                    if (start < i)
                                    {
                                        Console.Write(System.Text.Encoding.UTF8.GetString(ls, start, i - start));
                                    }
                                    start = i + 1;
                                    Console.ForegroundColor = ConsoleColor.Red;
                                    break;
                                case 7:
                                    if (start < i)
                                    {
                                        Console.Write(System.Text.Encoding.UTF8.GetString(ls, start, i - start));
                                    }
                                    start = i + 1;
                                    Console.ForegroundColor = ConsoleColor.DarkYellow;
                                    break;
                                case 8:
                                    if (start < i)
                                    {
                                        Console.Write(System.Text.Encoding.UTF8.GetString(ls, start, i - start));
                                    }
                                    start = i + 1;
                                    Console.ForegroundColor = ConsoleColor.DarkGreen;
                                    break;
                            }
                        }

                        if (start < total)
                        {
                            Array.Copy(ls, start, ls, 0, total - start);
                            index = total - start;
                            size = ls.Length - index;
                            start = 0;
                        }
                    }
                    while (total > index);
                    if (start < total)
                    {
                        Console.WriteLine(System.Text.Encoding.UTF8.GetString(ls, start, total - start));
                    }
                    Console.WriteLine();


                }
            }
            catch
            {
                Console.WriteLine("指令接收失败，请重新输入。");
            }
            finally
            {
                tcpClient.Close();
            }


        }
        static void Command(string[] args)
        {
            switch (args[0])
            {
                case "stop":
                    if (IsRun())
                    {
                        Write(args);
                    }
                    else
                    {
                        Console.WriteLine("ITME未开启，请开启。");
                    }
                    break;
                case "biome":
                case "ssl":
                case "dns":
                case "repost":
                case "clear":
                case "https":
                case "http":
                case "pool":
                    if (IsRun())
                    {
                        Write(args);
                    }
                    else
                    {
                        Console.WriteLine("ITME未开启，请开启。");
                    }
                    break;
                case "reset":
                    if (args.Length > 1)
                    {
                        Write(args);
                    }
                    else
                    {
                        Console.WriteLine("reset指令格式不正确");
                    }
                    break;
                case "restart":
                    if (IsRun() == false)
                    {
                        Excel("main", true);
                        Write("info");
                        IsDo = false;

                    }
                    else
                    {
                        Excel("main", true);
                        Console.WriteLine("正在重启IT管理引擎（ITME）服务");
                        // using (var pipeServer = new NamedPipeServerStream("APIUMCReStart", PipeDirection.InOut))
                        // {

                        //     var bufer = new byte[100];

                        //     // var IsEror = false;

                        //     try
                        //     {
                        //         pipeServer.WaitForConnection();

                        //         int l = pipeServer.Read(bufer, 0, 100);
                        //         Console.WriteLine(System.Text.Encoding.UTF8.GetString(bufer, 0, l));
                        //         Write("Stop");
                        //         pipeServer.Write(bufer, 0, "StopNet".WriteBytes(bufer, 0));

                        //         //.Split(' ');
                        //     }
                        //     catch
                        //     {

                        //     }

                        // }

                        Write("info");

                        IsDo = false;
                    }
                    // Write("info");
                    break;
                case "daemon":
                    {
                        if (IsRun() == false)
                        {
                            Excel("daemon", false);
                            IsDo = false;
                            int time = 0;
                            while (time < 20)
                            {
                                System.Threading.Thread.Sleep(500);
                                if (IsRun())
                                {
                                    break;
                                }
                                time++;
                            }
                            Write("info");
                        }
                        else
                        {
                            Write(args);
                        }
                    }
                    break;
                case "start":
                    if (IsRun() == false)
                    {
                        Excel("main", true);
                        IsDo = false;
                        int time = 0;
                        while (time < 20)
                        {
                            System.Threading.Thread.Sleep(500);
                            if (IsRun())
                            {
                                break;
                            }
                            time++;
                        }
                        Write("info");
                    }
                    else
                    {
                        Write(args);
                    }
                    break;
                default:
                    // if()
                    if (IsRun())
                    {
                        Write(args);
                    }
                    else
                    {
                        Console.WriteLine($"不能识别指令：[{args[0]}]");
                    }
                    // 
                    break;
            }
        }

        static Process Excel(string arg)
        {
            return Excel(arg, true);
        }
        static Process Excel(string arg, bool isRedirect)
        {
            var process = System.Diagnostics.Process.GetCurrentProcess();

            if (String.Equals(process.ProcessName.ToLower(), "dotnet"))
            {
                var file = Environment.GetCommandLineArgs()[0];
                ProcessStartInfo startInfo = new ProcessStartInfo("dotnet")
                {
                    // WindowStyle = ProcessWindowStyle.Hidden,
                    CreateNoWindow = true,
                    UseShellExecute = false,
                    RedirectStandardInput = false,
                    RedirectStandardError = isRedirect,
                    RedirectStandardOutput = isRedirect,
                    Arguments = System.IO.Path.GetFileName(file),
                    WorkingDirectory = System.IO.Path.GetDirectoryName(file)
                };
                startInfo.Environment.Add("UMC", arg);
                return Process.Start(startInfo);

            }
            else
            {
                var file = process.MainModule.FileName;
                ProcessStartInfo startInfo = new ProcessStartInfo(System.IO.Path.GetFileName(file))
                {
                    CreateNoWindow = true,
                    UseShellExecute = false,
                    RedirectStandardInput = false,
                    RedirectStandardError = isRedirect,
                    RedirectStandardOutput = isRedirect,
                    WorkingDirectory = System.IO.Path.GetDirectoryName(file)
                };
                startInfo.Environment.Add("UMC", arg);
                // startInfo.
                return Process.Start(startInfo);

            }
        }

        static void ConfigDbProvider()
        {
            var urlKey = RuntimeInformation.RuntimeIdentifier;
            var native = "/native/cavif";

            if (OperatingSystem.IsWindows())
            {
                native = "/native/cavif.exe";

                if (urlKey.EndsWith("x86"))
                {
                    urlKey = "win-x86";

                }
                else if (urlKey.EndsWith("x64"))
                {
                    urlKey = "win-x64";
                }
                else if (urlKey.EndsWith("arm"))
                {
                    urlKey = "win-arm64";

                }
            }
            else if (OperatingSystem.IsMacOS())
            {
                if (urlKey.EndsWith("arm64"))
                {

                    urlKey = "osx-arm64";
                }
                else
                {
                    urlKey = "osx-x64";

                }
            }
            else if (OperatingSystem.IsLinux())
            {
                if (urlKey.EndsWith("musl-x64"))
                {
                    urlKey = "linux-musl-x64";

                }
                else if (urlKey.EndsWith("x64"))
                {
                    urlKey = "linux-x64";
                }
                else if (urlKey.EndsWith("arm64"))
                {
                    urlKey = "linux-arm64";
                }
                else if (urlKey.EndsWith("arm"))
                {
                    urlKey = "linux-arm";

                }
            }
            if (String.IsNullOrEmpty(urlKey) == false)
            {
                var file = UMC.Data.Utility.MapPath(native);
                if (System.IO.File.Exists(file) == false)
                {

                    ManualResetEvent mre = new ManualResetEvent(false);
                    var url = new Uri($"https://wdk.oss-accelerate.aliyuncs.com/AppResources/{urlKey}.zip");
                    var downloadFile = file + ".download";
                    url.WebRequest().Get(r =>
                    {
                        if (r.StatusCode == HttpStatusCode.OK)
                        {
                            var count = r.ContentLength;
                            int size = 0;
                            var stream = Utility.Writer(downloadFile, false);
                            r.ReadAsData((b, c, l) =>
                            {
                                size += l;
                                if (b.Length == 0)
                                {
                                    Console.WriteLine();

                                    stream.Flush();
                                    stream.Close();
                                    stream.Dispose();
                                    try
                                    {
                                        System.IO.Compression.ZipFile.ExtractToDirectory(downloadFile, UMC.Data.Utility.MapPath("/"), true);
                                        if (native.EndsWith("exe"))
                                        {
                                            Utility.Move(UMC.Data.Utility.MapPath("/cavif.exe"), file);
                                        }
                                        else
                                        {
                                            Utility.Move(UMC.Data.Utility.MapPath("/cavif"), file);
                                        }
                                    }
                                    catch
                                    {
                                        Console.SetCursorPosition(0, Console.CursorTop);
                                        Console.WriteLine($"图片组件下载失败,影响图片功能");
                                    }
                                    File.Delete(downloadFile);
                                    mre.Set();
                                }
                                else
                                {
                                    Console.SetCursorPosition(0, Console.CursorTop);
                                    Console.Write($"正在下载图片组件{size * 100 / count:0}%");

                                    stream.Write(b, c, l);
                                }
                            });
                        }
                        else
                        {
                            Console.WriteLine("图片组件下载失败");
                            mre.Set();
                        }
                    });
                    mre.WaitOne();
                }
            }
        }
        static void Register()
        {

            UMC.Web.WebClient.Register(() => new UMC.Web.Activities.AccountFlow());
            UMC.Web.WebClient.Register(() => new UMC.Web.Activities.AccountBiometricActivity());
            UMC.Web.WebClient.Register(() => new UMC.Web.Activities.SettingsFlow());
            UMC.Web.WebClient.Register(() => new UMC.Web.Activities.SystemFlow());
            UMC.Web.WebClient.Register(() => new UMC.Web.Activities.SystemSetupActivity());
            UMC.Web.WebClient.Register(() => new UMC.Web.Activities.SettingsAreaActivity());
            UMC.Web.WebClient.Register(() => new UMC.Web.Activities.SettingsSelectOrganizeActivity());
            UMC.Web.WebClient.Register(() => new UMC.Web.Activities.SettingsSelectRoleActivity());
            UMC.Web.WebClient.Register(() => new UMC.Web.Activities.SettingsSelectUserActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.WebFactory());

            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteLicenseActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteBuilderActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SitePictureActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteScanningActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.HttpBridgeActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.HttpClientActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteAlertActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteGroupActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteCustomerActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteAppActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteAuthActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteConfActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteConfImageActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteLogActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteMimeActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteServerActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteUserActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.UIConfigActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteUIActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteSearchActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteSetupActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteUMCActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteMarketActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteSSHActivities());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteWebAuthnActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteOnlineActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteStaffActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteSecretActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteFirewallActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteFingerprintActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteBgSrcActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteForwardActivity());
            UMC.Web.WebClient.Register(() => new UMC.ITME.Activities.SiteDeviceActivity());

        }
        static void UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            var ex = e.ExceptionObject as Exception;
            var filename = UMC.Data.Reflection.ConfigPath(String.Format("Static\\log\\App\\Error\\ITME\\{0:yy-MM-dd}.log", DateTime.Now));
            if (!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(filename)))
            {
                System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(filename));
            }
            ITME.HttpMimeServier.Stop();
            File.AppendAllText(filename, $"{DateTime.Now}:{ex}\r\n");// ex.ToString());

            Excel($"main");
        }
        static void StartUp(string[] args, Action action, Dictionary<String, Func<String>> keyValues, Func<UMC.ITME.WebServlet> func = null)
        {
            // 
            try
            {
                var p = typeof(Program).Assembly.GetCustomAttributes().FirstOrDefault(r => r is System.Reflection.AssemblyInformationalVersionAttribute) as System.Reflection.AssemblyInformationalVersionAttribute;
                APIProxy.Version = p?.InformationalVersion ?? "1.0.0";
            }
            catch
            {

            }

            //UMC.Data.HotCache.BuilderCode(typeof(Entities.ProxySite));
            System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);

            UMC.ITME.DataFactory.Instance();
            UMC.Data.DataFactory.Instance();

            bool IsSync = false;
            if (args.Length > 0)
            {
                if (String.IsNullOrEmpty(args[0]) == false)
                {
                    IsSync = true;
                    UMC.Data.Reflection.Instance().SetBaseDirectory(args[0]);
                }
            }
            action?.Invoke();
            Register();



            ITME.HttpMimeServier.Start(IsSync, keyValues, func);

        }

    }
}
